package xuesm.proxy.dynamic.facemeng;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @Author: xuesm
 * @Description:
 * @Date: Create in 13:02 2019/4/3
 */
public class FMProxy {


	public final static String ln = "\r\n";

	public static Object newProxyInstance(FMClassLoader fmClassLoader, Class<?>[] interfaces, FMInvocationHandler handler) {

		try {
			// 1. 动态生成.java文件
			String src = generateSrc(interfaces);
			// 2. java文件输出到磁盘
			String filePath = FMProxy.class.getResource("").getPath();
			File file = new File(filePath + "$Proxy0.java");
			FileWriter fileWriter = new FileWriter(file);
			fileWriter.write(src);
			fileWriter.flush();
			fileWriter.close();
			// 3. java文件编译成class文件
			JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
			StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
			Iterable iterable = manager.getJavaFileObjects(file);
			JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
			task.call();
			manager.close();

			// 4. class文件加载到JVM中
			Class proxyClass = fmClassLoader.findClass("$Proxy0");
			Constructor constructor = proxyClass.getConstructor(FMInvocationHandler.class);
			file.delete();
			return constructor.newInstance(handler);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}

	/**
	 * 动态生成.java文件
	 * @param interfaces
	 * @return
	 */
	private static String generateSrc(Class<?>[] interfaces) {

		StringBuffer buffer = new StringBuffer();

		buffer.append("package xuesm.proxy.dynamic.facemeng;" + ln);
		buffer.append("import xuesm.proxy.IPlayer;" + ln);
		buffer.append("import java.lang.reflect.Method;" + ln);

		buffer.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);

			buffer.append("FMInvocationHandler h;" + ln);
			buffer.append("public $Proxy0(FMInvocationHandler h){" + ln);
				buffer.append("this.h = h;" + ln);
			buffer.append("}" + ln);

			for (Method method : interfaces[0].getMethods()){
				buffer.append("public " + method.getReturnType().getName() + " " + method.getName() + "(){" +ln);
					buffer.append("try{" + ln);
						buffer.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + method.getName() + "\", new Class[]{});" + ln);
						buffer.append("this.h.invoke(this, m, null);" + ln);
					buffer.append("} catch(Throwable e){" + ln);
						buffer.append("e.printStackTrace();" + ln);
					buffer.append("}" +ln);
				buffer.append("}" + ln);
			}


		buffer.append("}");



		return buffer.toString();
	}
}
